/*****************************************************************************\
*              efs - General purpose Embedded Filesystem library              *
*          --------------------- -----------------------------------          *
*                                                                             *
* Filename : atmega128.c                                                      *
* Description : This file contains the functions needed to use efs for        *
*               accessing files on an SD-card connected to an ATMega128.      *
*                                                                             *
* This program is free software; you can redistribute it and/or               *
* modify it under the terms of the GNU General Public License                 *
* as published by the Free Software Foundation; version 2                     *
* of the License.                                                             *
                                                                              *
* This program is distributed in the hope that it will be useful,             *
* but WITHOUT ANY WARRANTY; without even the implied warranty of              *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
* GNU General Public License for more details.                                *
*                                                                             *
* As a special exception, if other files instantiate templates or             *
* use macros or inline functions from this file, or you compile this          *
* file and link it with other works to produce a work based on this file,     *
* this file does not by itself cause the resulting work to be covered         *
* by the GNU General Public License. However the source code for this         *
* file must still be made available in accordance with section (3) of         *
* the GNU General Public License.                                             *
*                                                                             *
* This exception does not invalidate any other reasons why a work based       *
* on this file might be covered by the GNU General Public License.            *
*                                                                             *
*                                                    (c)2006 Lennart Yseboodt *
*                                                    (c)2006 Michael De Nil   *
\*****************************************************************************/

/*****************************************************************************/
#include "atmega128.h"
#include "sd.h"
#include "includes.h"
/*****************************************************************************/

#define SD_CP      GPIO_Pin_7
#define SD_WP      GPIO_Pin_6

#define SD_CS      GPIO_Pin_12
#define SD_SCLK    GPIO_Pin_13
#define SD_MOSI    GPIO_Pin_14
#define SD_MISO    GPIO_Pin_15

#define IdentificationModeClock   (200KHZ)

esint8 if_initInterface(hwInterface* file, eint8* opts)
{
	if_spiInit(file);
	if(sd_Init(file)<0)	{
//		DBG((TXT("Card failed to init, breaking up...\n")));
		return(-1);
	}
	if(sd_State(file)<0){
//		DBG((TXT("Card didn't return the ready state, breaking up...\n")));
		return(-2);
	}
	file->sectorCount=4; /* FIXME ASAP!! */
//	DBG((TXT("Init done...\n")));
	return(0);
}
/*****************************************************************************/ 

esint8 if_readBuf(hwInterface* file,euint32 address,euint8* buf)
{
	return(sd_readSector(file,address,buf,512));
}
/*****************************************************************************/

esint8 if_writeBuf(hwInterface* file,euint32 address,euint8* buf)
{
	return(sd_writeSector(file,address, buf));
}
/*****************************************************************************/ 

esint8 if_setPos(hwInterface* file,euint32 address)
{
	return(0);
}
/*****************************************************************************/ 

/*************************************************************************
 * Function Name: MmcChipSelect
 * Parameters: Boolean Select
 * Return: none
 *
 * Description: Mmc Chip select control
 * Select = true  - Chip is enable
 * Select = false - Chip is disable
 *
 *************************************************************************/
void MmcChipSelect (Boolean Select)
{
  GPIO_WriteBit(GPIOB,SD_CS,Select?Bit_RESET:Bit_SET);
}

/*************************************************************************
 * Function Name: MmcSetClockFreq
 * Parameters: Int32U Frequency
 * Return: Int32U
 *
 * Description: Set SPI ckl frequency
 *
 *************************************************************************/
Int32U MmcSetClockFreq (Int32U Frequency)
{
Int32U Div = 2;
Int32U DivVal = 0;
RCC_ClocksTypeDef Clk;

  RCC_GetClocksFreq(&Clk);

  while((Frequency * Div) <=  Clk.PCLK1_Frequency)
  {
    Div <<= 1;
    if (++DivVal == 7)
    {
      break;
    }
  }

  SPI2->CR1 = (SPI2->CR1 & ~(0x7 << 3)) | ((DivVal&0x7) << 3);

  // Return real frequency
  return(Clk.PCLK1_Frequency/Div);
}


void if_spiInit(hwInterface *iface)
{
  
	euint8 i;
	
        SPI_InitTypeDef   SPI_InitStructure;
        GPIO_InitTypeDef  GPIO_InitStructure;
      
        // Enable GPIO clocks
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
        // Enable SPI2 Periphery clock
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
      
        // Deinitializes the SPI2
        SPI_DeInit(SPI2);
        // Release reset of GPIOB, GPIOC
        RCC_APB2PeriphResetCmd(  RCC_APB2Periph_GPIOB
                               | RCC_APB2Periph_GPIOC, DISABLE);
      
        // Configure SPI2_CLK, SPI2_MOSI, SPI2_nCS1, Card Present and Write Protect pins
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Pin = SD_CS;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
      
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Pin = SD_SCLK | SD_MOSI | SD_MISO;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
      
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_InitStructure.GPIO_Pin = SD_CP | SD_WP;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
      
        // Chip select
        MmcChipSelect(0);
      
        // Spi init
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
        SPI_InitStructure.SPI_CRCPolynomial = 7;
        SPI_Init(SPI2, &SPI_InitStructure);
      
        // Enable SPI2 */
        SPI_Cmd(SPI2, ENABLE);
      
        // Clock Freq. Identification Mode < 400kHz
        MmcSetClockFreq(IdentificationModeClock);
        

	/* Send 10 spi commands with card not selected */
	for(i=0;i<10;i++)
		if_spiSend(iface,0xff);

       // Chip select
        MmcChipSelect(1);
        
}
/*****************************************************************************/

euint8 if_spiSend(hwInterface *iface, euint8 outgoing)
{
	euint8 incoming=0;
	
        
          /* Loop while DR register in not emplty */
        while(SPI_GetFlagStatus(SPI2, SPI_FLAG_TXE) == RESET);
      
        /* Send byte through the SPI1 peripheral */
        SPI_SendData(SPI2, outgoing);
      
        /* Wait to receive a byte */
        while(SPI_GetFlagStatus(SPI2, SPI_FLAG_RXNE) == RESET);
      
        /* Return the byte read from the SPI bus */
        incoming = SPI_ReceiveData(SPI2);

	return(incoming);
}
/*****************************************************************************/

